package com.gitee.wsl.doc.prosemirror.ui

import com.gitee.wsl.doc.prosemirror.state.Command
import com.gitee.wsl.doc.prosemirror.state.EditorStateConfig
import com.gitee.wsl.doc.prosemirror.state.EditorState
import com.gitee.wsl.doc.prosemirror.state.Transaction
import com.gitee.wsl.doc.prosemirror.state.selection.NodeSelection
import com.gitee.wsl.doc.prosemirror.state.selection.Selection
import com.gitee.wsl.doc.prosemirror.state.selection.TextSelection
import com.gitee.wsl.doc.prosemirror.transform.Transform
import kotlinx.coroutines.flow.MutableStateFlow

class EditorViewModel(val stateFlow: MutableStateFlow<EditorState>) {

    val state: EditorState
        get() = stateFlow.value
    val doc
        get() = this.state.doc
    val selection: Selection
        get() = this.state.selection
    val tr: Transaction
        get() = this.state.tr

    constructor(config: EditorStateConfig):this(MutableStateFlow(EditorState.Companion.create(config))) {
        //        if (config.selection == null && config.doc != null) {
        //            config.selection = selFor(config.doc!!)
        //        }
        //this.state = PMEditorState.create(config)
    }

    fun apply(tr: Transaction) {
        this.stateFlow.value = this.state.apply(tr)
    }

    fun transaction(f: Transaction.() -> Transform){
        this.apply(tr.apply { f() })
    }

    fun command(cmd: (state: EditorState, (tr: Transaction) -> Unit) -> Unit) {
        cmd(this.state) { tr -> this.apply(tr) }
    }

    fun command(cmd: Command) {
        cmd(this.state) { tr -> this.apply(tr) }
    }

    fun type(text: String) {
        this.apply(this.tr.insertText(text))
    }

    fun deleteSelection() {
        this.apply(this.state.tr.deleteSelection())
    }

    fun textSelection(anchor: Int, head: Int? = null) {
        val sel = TextSelection.Companion.create(this.state.doc, anchor, head)
        this.stateFlow.value = this.state.apply(this.state.tr.setSelection(sel))
    }

    fun nodeSelection(pos: Int) {
        val sel = NodeSelection.Companion.create(this.state.doc, pos)
        this.stateFlow.value = this.state.apply(this.state.tr.setSelection(sel))
    }
}